package com.yzr.demo10;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Assertions;
import org.springframework.util.StopWatch;

import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Slf4j
public class Test01 {
    //不能使用Arrays.asList来转换基本类型数组
    //反例
    public static void fun1(){
        int[] arr = { 1,2,3};
        List list = Arrays.asList(arr);
        log.info("list:{} size:{} class:{}",list,list.size(),list.get(0).getClass());
    }
    //正例
    public static void fun2(){
        Integer[] arr = { 1,2,3};
        List list = Arrays.asList(arr);
        log.info("list:{} size:{} class:{}",list,list.size(),list.get(0).getClass());
    }
    //正例
    //Arrays.asList生成的list不能进行增删操作
    public static void fun3(){
        int[] arr = { 1,2,3};
        List list = Arrays.stream(arr).boxed().collect(Collectors.toList());
        log.info("list:{} size:{} class:{}",list,list.size(),list.get(0).getClass());
        System.out.println(list.remove(0));
    }

    public static void fun4(){
        int[] arr = { 1,2,3};
        List list = Arrays.stream(arr).boxed().collect(Collectors.toList());
        log.info("list:{} size:{} class:{}",list,list.size(),list.get(0).getClass());
        System.out.println(list.get(0));
    }

    //建议使用 new ArrayLIst创建集合，避免与元数组共享数组产生异常
    public static void fun5(){
        String[] arr = {"1", "2", "3"};
        List list = new ArrayList(Arrays.asList(arr));
        arr[1] = "4";
        try {
            list.add("5");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        log.info("arr:{} list:{}", Arrays.toString(arr), list);
    }

    private static List<List<Integer>> data = new ArrayList<>();

    //在进行subList的时候会对数组产生强引用导致无法被gc回收，导致oom
    private static void oom(){
        for (int i = 0; i < 1000; i++) {
            List<Integer> rawList = IntStream.rangeClosed(1, 100000).boxed().collect(Collectors.toList());
            data.add(rawList.subList(0,1));
        }
    }
    private static void fun6(){
        //创建并维护一个modCount
        List<Integer> list = IntStream.rangeClosed(1, 10).boxed().collect(Collectors.toList());
        //subList会复制list的modCount
        List<Integer> subList = list.subList(1, 4);
        //方式一使用new
        //List<Integer> subList = new ArrayList<>(list.subList(1, 4));
        //方式二使用stream流
        //List subList = list.stream().skip(1).limit(3).collect(Collectors.toList());
        System.out.println(subList);
        subList.remove(1);
        System.out.println(list);
        //在list使用add方法modCount会+1
        list.add(0);
        try {
            //遍历subList的时候会判断和list的modCount是否相等，不相等就抛出异常
            subList.forEach(System.out::println);
        }catch (Exception exception){
            exception.printStackTrace();
        }
    }


    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    static class Order {
        private int orderId;
    }

    private static Object listSearch(int elementCount,int loopCount){
        List<Order> list = IntStream.rangeClosed(1, elementCount).mapToObj(i -> new Order(i)).collect(Collectors.toList());
        IntStream.rangeClosed(1,loopCount).forEach(i->{
            int search = ThreadLocalRandom.current().nextInt(elementCount);
            Order result = list.stream().filter(order->order.getOrderId()==search).findFirst().orElse(null);
            Assertions.assertTrue(result != null && result.getOrderId() == search);
//            MatcherAssert.assertThat("ture",result != null && result.getOrderId() == search);
        });
        return list;
    }


    private static Object mapSearch(int elementCount, int loopCount) {
        Map<Integer, Order> map = IntStream.rangeClosed(1, elementCount).boxed().collect(Collectors.toMap(Function.identity(), i -> new Order(i)));
        IntStream.rangeClosed(1, loopCount).forEach(i -> {
            int search = ThreadLocalRandom.current().nextInt(elementCount);
            Order result = map.get(search);
            Assertions.assertTrue(result != null && result.getOrderId() == search);
        });
        return map;
    }
    private static void fun7(){

        int elementCount = 1000000;
        int loopCount = 1000;
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("listSearch");
        //时间长 空间小
        Object list = listSearch(elementCount, loopCount);
//        System.out.println(ObjectSizeCalculator.getObjectSize(list));
        stopWatch.stop();
        stopWatch.start("mapSearch");
        //时间短 空间长
        Object map = mapSearch(elementCount, loopCount);
        stopWatch.stop();
//        System.out.println(ObjectSizeCalculator.getObjectSize(map));
        System.out.println(stopWatch.prettyPrint());
    }


    //LinkedList访问
    private static void linkedListGet(int elementCount, int loopCount) {
        List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed().collect(Collectors.toCollection(LinkedList::new));
        IntStream.rangeClosed(1, loopCount).forEach(i -> list.get(ThreadLocalRandom.current().nextInt(elementCount)));
    }

    //ArrayList访问
    private static void arrayListGet(int elementCount, int loopCount) {
        List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed().collect(Collectors.toCollection(ArrayList::new));
        IntStream.rangeClosed(1, loopCount).forEach(i -> list.get(ThreadLocalRandom.current().nextInt(elementCount)));
    }

    //LinkedList插入
    private static void linkedListAdd(int elementCount, int loopCount) {
        List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed().collect(Collectors.toCollection(LinkedList::new));
        IntStream.rangeClosed(1, loopCount).forEach(i -> list.add(ThreadLocalRandom.current().nextInt(elementCount),1));
    }

    //ArrayList插入
    private static void arrayListAdd(int elementCount, int loopCount) {
        List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed().collect(Collectors.toCollection(ArrayList::new));
        IntStream.rangeClosed(1, loopCount).forEach(i -> list.add(ThreadLocalRandom.current().nextInt(elementCount),1));
    }
    private static void fun8(){

        int elementCount = 100000;
        int loopCount = 100000;
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("linkedListGet");
        linkedListGet(elementCount, loopCount);
        stopWatch.stop();
        stopWatch.start("arrayListGet");
        arrayListGet(elementCount, loopCount);
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());


        StopWatch stopWatch2 = new StopWatch();
        stopWatch2.start("linkedListAdd");
        linkedListAdd(elementCount, loopCount);
        stopWatch2.stop();
        stopWatch2.start("arrayListAdd");
        arrayListAdd(elementCount, loopCount);
        stopWatch2.stop();
        System.out.println(stopWatch2.prettyPrint());
    }
    public static void main(String[] args) {
//        fun1();
//        fun2();
//        fun4();
//        fun5();
//        fun5();
//        oom();
//        fun6();
//          fun7();
          fun8();
    }
}































